home *** CD-ROM | disk | FTP | other *** search
- /* Asynchronous file input/output routines (c) Stone, The SST
- Public domain. email: c9107253@cs.newcastle.edu.au
-
- See example programs for usage
- */
-
- #include <exec/types.h>
- #include <exec/memory.h>
- #include <exec/ports.h>
- #include <dos/dos.h>
- #include <dos/dosextens.h>
- #include <proto/exec.h>
- #include <proto/dos.h>
- #include <st/st_proto.h>
-
- /*
- NOTE: Becareful on implicit GetMsg's & Waits when calling ARead, AWrite,
- AStatus or AResultWait. Always keep all GetMsg's in a single loop! (so
- resort to AStatusQuick and AGetReply)
- */
-
-
- /*********************************************************/
- long ASigBit(struct AFileHandle *afh)
- /*********************************************************
- Call this to find the bit to wait on when waiting for
- replies from the associated file
- Note that several files may share the same reply port
- so all files sharing the port must be checked with AStatus
- *********************************************************/
- { return(ASIGBIT(afh)); }
-
-
- /*********************************************************/
- long AResult(struct AFileHandle *afh)
- /*********************************************************/
- { return(ARESULT1(afh)); }
-
-
- /*********************************************************/
- long AStatusQuick(struct AFileHandle *afh)
- /*********************************************************/
- { return(afh->Status); }
-
-
- /*********************************************************/
- struct AFileHandle *AGetReply(struct APort *aport)
- /*********************************************************
- Attempt GetMsg a single message from the port
- *********************************************************/
- { struct AFileHandle *afh;
- if(afh = (struct AFileHandle *)GetMsg(aport->Port))
- afh->Status = ASTATUS_IDLE;
- return(afh);
- }
-
-
- /*********************************************************/
- long AStatus(struct AFileHandle *afh)
- /*********************************************************
- Return the status if not busy
- If busy remove messages until no more or we found our reply
- WARNING: this possibly removes all pending messages
- so be VERY careful with this and a 'Wait'
- (best to use this with only a single file)
- *********************************************************/
- {
- struct AFileHandle *afh_reply;
- if(afh->Status != ASTATUS_BUSY) return(afh->Status);
- while(afh_reply = AGetReply(afh->APort)) if(afh_reply == afh) break;
- return(afh->Status);
- }
-
-
- /*********************************************************/
- long AResultWait(struct AFileHandle *afh)
- /*********************************************************
- Wait until status is NOT ASTATUS_BUSY
- Be careful with this routine also (see AStatus)
- *********************************************************/
- {
- while(AStatus(afh) == ASTATUS_BUSY) Wait(1<<ASIGBIT(afh));
- return(ARESULT1(afh));
- }
-
-
- /*********************************************************/
- void AClose(struct AFileHandle *afh)
- /*********************************************************
- Close a file
- Note: IF A PACKET IS PENDING THIS WILL WAIT AND ALL MSG'S
- UP TO THIS PACKET WILL BE AGetReply'd
- (so AStatus all other files if this is the case)
- *********************************************************/
- {
- if(!afh) return;
-
- /** WAIT FOR THE PENDING PACKET IF NEED BE */
- AResultWait(afh);
-
- /** UNLINK US FROM THE PORT LIST OF OPEN FILES */
- if(afh->Prev)
- afh->Prev->Next = afh->Next;
- else afh->APort->First = afh->Next;
- if(afh->Next)
- afh->Next->Prev = afh->Prev;
-
- /** CLOSE THE FILE & FREE THE MEMORY */
- if(afh->FileHandle && (afh->Flags&AFLAG_CLOSEONCLOSE))
- Close(((long)afh->FileHandle)>>2);
- FreeMem(afh,sizeof(struct AFileHandle));
- }
-
-
- /*********************************************************/
- void ASafeClose(struct AFileHandle **afh)
- /*********************************************************/
- { if(*afh) { AClose(*afh); *afh = 0; } }
-
-
- /*********************************************************/
- struct AFileHandle
- *AMakeFD2AFD(struct APort *aport, long fd)
- /*********************************************************
- Build an AFileDescriptor from the fd passed in
- Default to no auto file close
- (so Input() can be copied)
- *********************************************************/
- {
- struct AFileHandle *afh;
- if(!aport || !fd ||
- !(afh = AllocMem(sizeof(struct AFileHandle),MEMF_PUBLIC | MEMF_CLEAR)))
- return(0);
- afh->FileHandle = (struct FileHandle *)(fd<<2);
- afh->Prev = 0;
- if(afh->Next = aport->First) afh->Next->Prev = afh;
- afh->APort = aport;
- afh->Status = ASTATUS_FIRSTTIME;
- afh->Flags = AFLAG_NOCLOSE;
- aport->First = afh;
- return(afh);
- }
-
- /*********************************************************/
- struct AFileHandle
- *AOpen(struct APort *aport, char *name, long mode)
- /*********************************************************
- Attempt to open a file with 'mode' and link into the
- list of open files on the port APort
- return NULL if file could not be opened or no memory
- **********************************************************/
- {
- long fd;
- struct AFileHandle *afh;
- if(!(fd = Open(name, mode) )) return(0);
- if(!(afh = AMakeFD2AFD(aport, fd))) {
- Close(fd); return(0);
- }
- /* CLOSE ACTUAL FILE ON A DELETE PORT OR EXPLICIT CLOSE */
- afh->Flags = AFLAG_CLOSEONCLOSE;
- return(afh);
- }
-
-
-
-
-
- /*********************************************************/
- void ADeletePort(struct APort *aport)
- /*********************************************************
- Close & Free all opened files on this port
- Delete the port
- **********************************************************/
- {
- if(!aport) return;
- while(aport->First) AClose(aport->First);
- DeletePort(aport->Port);
- FreeMem(aport, sizeof(struct APort));
- }
-
-
- /*********************************************************/
- struct APort *ACreatePort(void)
- /*********************************************************
- Create a reply port for the dos packets
- **********************************************************/
- {
- struct APort *aport;
- if(!(aport = (struct APort *)
- AllocMem(sizeof(struct APort), MEMF_PUBLIC | MEMF_CLEAR)))
- return(0);
- spf(aport->PortName, APORTNAMESIZE, "AIOReply.%08lx", aport);
- if(!(aport->Port = CreatePort(aport->PortName, 0)))
- { FreeMem(aport, sizeof(struct APort)); return(0); }
- aport->First = 0;
- return(aport);
- }
-
-
-
- /*********************************************************/
- short ASendPacket(struct AFileHandle *afh, long action,
- long arg1, long arg2, long arg3, long arg4)
- /*********************************************************
- Try and send a packet using the given handle
- return 1 on ok, 0 if packet is already in use
- *********************************************************/
- {
- struct StandardPacket *sp = &(afh->Pkt);
- struct MsgPort *port = afh->FileHandle->fh_Type;
- if(afh->Status == ASTATUS_BUSY) return(0);
- afh->Status = ASTATUS_BUSY;
-
- /** ADDRESS NEGATIVE IF PLAIN FILE?? (I don't believe...) */
- sp->sp_Msg.mn_Node.ln_Name =(char *)&(sp->sp_Pkt);
- sp->sp_Pkt.dp_Link = &(sp->sp_Msg);
- sp->sp_Pkt.dp_Port = afh->APort->Port;
- sp->sp_Pkt.dp_Type = action;
- sp->sp_Pkt.dp_Arg1 = arg1;
- sp->sp_Pkt.dp_Arg2 = arg2; /* DESTINATION */
- sp->sp_Pkt.dp_Arg3 = arg3; /* BUFSIZE */
- sp->sp_Pkt.dp_Arg4 = arg4; /* ANOTHER THING */
-
- PutMsg(port, &(sp->sp_Msg));
- return(1);
- }
-
-
-
-
- /*********************************************************/
- long ARead(struct AFileHandle *afh, void *buf, long n)
- /*********************************************************
- Send a packet to read
- This returns the results of the PREVIOUS packet
- of THIS filehandle
- NOTE that the new packet is sent ONLY if the previous
- packet result is OK
- **********************************************************/
- {
- long prev_res;
- if(AStatus(afh) == ASTATUS_FIRSTTIME) prev_res = -1;
- else prev_res = AResultWait(afh);
- if(prev_res) ASendPacket(afh, ACTION_READ,
- afh->FileHandle->fh_Args, (long)buf, n, 0);
- return(prev_res);
- }
-
- /*********************************************************/
- long AWrite(struct AFileHandle *afh, void *buf, long n)
- /*********************************************************
- Send a packet to write
- This returns the results of the PREVIOUS packet
- of THIS filehandle
- NOTE that the new packet is sent ONLY if the previous
- packet result is OK
- **********************************************************/
- {
- long prev_res;
- if(AStatus(afh) == ASTATUS_FIRSTTIME) prev_res = -1;
- else prev_res = AResultWait(afh);
- if(prev_res) ASendPacket(afh, ACTION_WRITE,
- afh->FileHandle->fh_Args, (long)buf, n, 0);
- return(prev_res);
- }
-